--add res
resource.AddFile("materials/models/drew/submass.vmt")
resource.AddFile("materials/models/drew/submass.vtf")
resource.AddFile("materials/models/drew/submass_normal.vtf")
resource.AddFile("sound/geiger.wav")
resource.AddFile("materials/jaanus/nukecase.vmt")
resource.AddFile("materials/jaanus/nukecase.vtf")
resource.AddFile("materials/jaanus/nukemisc.vtf")
resource.AddFile("materials/jaanus/nukemisc_mask.vtf")
resource.AddFile("materials/jaanus/w_c4.vmt")
resource.AddFile("materials/jaanus/w_c4.vtf")
resource.AddFile("models/jaanus/nuke.dx80.vtx")
resource.AddFile("models/jaanus/nuke.dx90.vtxx")
resource.AddFile("models/jaanus/nuke.sw.vtx")
resource.AddFile("models/jaanus/nuke.phy")
resource.AddFile("models/jaanus/nuke.vvd")
resource.AddFile("models/jaanus/nuke.xbox.vtx")
-- shanjaq: Start Life Support mod.
AddCSLuaFile( "autorun/client/cl_lifesupport.lua" )

--Compatibility Global
LIFESUPPORT = 1

FairTemp = 288
local DrownDamage = 10
local Energy_Increment = 5
local Air_Increment = 5
local Coolant_Increment = 5
local NextUpdateTime = 0
local hfix = 0
local tfix = 0
local EnvShields = true --allow my Personal shield SWEP to protect from space?

local WaterCheck = {}

util.PrecacheSound( "streetwar.slimegurgle04" )
util.PrecacheSound( "Player.FallGib" )


function LSWaterCheck()
	local i = 1
	while ( i <= #WaterCheck ) do
		if ( WaterCheck[i]:IsValid() ) then
			local entpos = WaterCheck[i]:GetPos()
			local trace = {}
				trace.start = entpos
				trace.endpos = entpos + Vector(0,0,10)
				trace.filter = { WaterCheck[i] }
				trace.mask = MASK_WATER
			local tr = util.TraceLine( trace )
			if (tr.Hit) then
				WaterCheck[i].environment.inwater = 1
			else
				WaterCheck[i].environment.inwater = 0
			end
			i = i + 1
		else
			table.remove( WaterCheck, i )
		end
	end

end


function LS_RegisterEnt( ent )
	local hash = {}
	hash.temperature = FairTemp
	hash.atmosphere = 1
	hash.habitat = 1
	hash.inwater = 0
	
	local rtable = {
		environment = hash
		}

	table.Merge(ent:GetTable(), rtable )
	table.insert(WaterCheck, ent)
end

function Suit_Register( pl )

	local hash = { }
	hash.player = pl
	hash.habitat = 1
	hash.inwater = 0
	hash.atmosphere = 1
	hash.temperature = FairTemp
	hash.air = 100
	hash.energy = 100
	hash.coolant = 100
	hash.recover = 0
	Msg ( "Adding Player\n" )
	pl.suit = hash
--	Suit_Update( pl.suit )

end

function LS_Setup()
	if (SunAngle == nil) then SunAngle = Vector(0,0,-1) end
end
hook.Add( "InitPostEntity", "LS_Setup", LS_Setup )


function Suit_Reset( s )
	s.recover = 0
	s.inwater = 0
	s.air = 100
	s.energy = 100
	s.coolant = 100
	s.habitat = 1
	s.atmosphere = 1
	s.temperature = FairTemp
--	Suit_Update( pl.suit )

end

function Suit_Update( s )
--	local rp = RecipientFilter()	-- Grab a RecipientFilter object
--	rp:AddPlayer(s.player)		-- Send to one player!
	if ( s.temperature < FairTemp ) then
		umsg.Start("LS_umsg", s.player)
			umsg.Short( (s.habitat + 1) )
			umsg.Short( s.air )
			umsg.Short( s.temperature )
			umsg.Short( s.energy )
		umsg.End() 
	else
		umsg.Start("LS_umsg", s.player)
			umsg.Short( (s.habitat + 1) )
			umsg.Short( s.air )
			umsg.Short( s.temperature )
			umsg.Short( s.coolant )
		umsg.End() 
	end	
end


function Pressure_Update( s )
	if ( s.atmosphere > 1) then
		if (s.player.Entity:Health() > 0) then
			s.player.Entity:TakeDamage( 100, 0 )
			LS_Crush( s.player )
		end
	end
end

function Air_Update( s )
	if ( s.air <= 0 ) then
		if (s.player.Entity:Health() > DrownDamage) then
			s.player.Entity:TakeDamage( DrownDamage, 0 )
			s.recover = s.recover + DrownDamage
			s.player.Entity:EmitSound( "Player.DrownStart" )
		else
			if (s.player.Entity:Health() > 0) then
				Suit_Reset( s )
				s.player.Entity:TakeDamage( DrownDamage, 0 )
				s.player.Entity:EmitSound( "streetwar.slimegurgle04" )
				s.player.Entity:EmitSound( "streetwar.slimegurgle04" )
				s.player.Entity:EmitSound( "streetwar.slimegurgle04" )
			end
		end

	else
		s.air = s.air - Air_Increment
	end
end

function Temperature_Update( s )
	local pPlayer = s.player.Entity
	local dec = 0
	if ( s.temperature < FairTemp ) then
		HurtAmt = ((FairTemp - s.temperature) / 5)
		if (s.atmosphere > 0) then
			dec = math.ceil(Energy_Increment * (4 - (s.temperature / 72)))
		else
			dec = Energy_Increment
		end
		if (s.energy > dec) then
			s.energy = s.energy - dec
		else
			s.energy = 0
			if (s.atmosphere > 0) then
				if (pPlayer:Health() <= HurtAmt) then
					if (pPlayer:Health() > 0) then
						pPlayer:TakeDamage( HurtAmt, 0 )
						LS_Frosty(pPlayer)
						Suit_Reset( s )
					end
				else
					pPlayer:TakeDamage( HurtAmt, 0 )
					s.recover = s.recover + HurtAmt
				end
			else
				if (pPlayer:Health() <= 7) then
					if (pPlayer:Health() > 0) then
						pPlayer:TakeDamage( 7, 0 )
						LS_Frosty(pPlayer)
						Suit_Reset( s )
					end
				else
					pPlayer:TakeDamage( 7, 0 )
					s.recover = s.recover + 7
				end
			end
		end
	elseif ( s.temperature > FairTemp ) then
		HurtAmt = ((s.temperature - FairTemp) / 5)
		dec = math.ceil(Coolant_Increment * ((s.temperature - FairTemp) / 72))
		if (s.coolant > dec) then
			s.coolant = s.coolant - dec
		else
			s.coolant = 0
			if (pPlayer:Health() <= HurtAmt) then
				if (pPlayer:Health() > 0) then
					LS_Immolate(pPlayer)
					pPlayer:TakeDamage( HurtAmt, 0 )
					Suit_Reset( s )
				end
			else
				pPlayer:TakeDamage( HurtAmt, 0 )
				s.recover = s.recover + HurtAmt
			end
		end
	end
end


function Life_Support_Update ()
	if ( CurTime() > NextUpdateTime ) then
	local pods = ents.FindByClass( "prop_vehicle_*" )
		for _, check in pairs( pods ) do
			if (check.environment == nil) then
				LS_RegisterEnt(check)
				RD_AddResource(check, "air", 0)
				RD_AddResource(check, "energy", 0)
				RD_AddResource(check, "coolant", 0)
			end
		end
	
		local tAllPlayers = player.GetAll()
		NextUpdateTime = CurTime() + 1
		for _, pPlayer in pairs( tAllPlayers ) do
			local entpos = pPlayer.Entity:GetPos()
			if ( pPlayer.Entity:Health() <= 0 ) then
				Suit_Reset( pPlayer.suit )
			end
			LSWaterCheck()  --check ents for water
			pPlayer.suit.inwater = 0  --begin better water check
			local trace = {}
				trace.start = entpos + Vector(0,0,50)
				trace.endpos = entpos + Vector(0,0,64)
				trace.filter = { pPlayer.Entity }
				trace.mask = MASK_WATER
			local tr = util.TraceLine( trace )
			if (tr.Hit) then pPlayer.suit.inwater = 1 end  --end better water check
			if (((pPlayer.suit.inwater == 1) or (pPlayer.suit.habitat == 0)) or ((pPlayer.suit.temperature != FairTemp) or (pPlayer.suit.atmosphere != 1))) then
				local airsafe = 0
				local heatsafe = 0
				local crushsafe = 0
				local pod = pPlayer:GetParent()
				if (pod:IsValid()) then
					if not (pod.environment == nil) then
						if (pod.environment.habitat == 0) then
							local inc = Air_Increment
							local avail = RD_GetResourceAmount(pod, "air")
							if (pPlayer.suit.air < 100) then
								if (avail >= (100 - pPlayer.suit.air)) then
									pPlayer.suit.air = 100
									inc = (inc + (100 - pPlayer.suit.air))
								end
							end
							if (avail >= inc) then
								RD_ConsumeResource(pod, "air", inc)
								airsafe = 1
							elseif (avail > 0) then
								RD_ConsumeResource(pod, "air", avail)
								pPlayer.suit.air = pPlayer.suit.air + avail
							end
						end
						if (pod.environment.temperature < FairTemp) then
							local e_dec = 0
							if (pod.environment.atmosphere > 0) then
								e_dec = math.ceil(Energy_Increment * (4 - (pod.environment.temperature / 72)))
							else
								e_dec = 2
							end
							if (RD_GetResourceAmount(pod, "energy") > e_dec) then
								RD_ConsumeResource(pod, "energy", e_dec)
								heatsafe = 1
							end
						elseif (pod.environment.temperature > FairTemp) then
							local c_dec = math.ceil(Coolant_Increment * ((pod.environment.temperature - FairTemp) / 72))
							if (RD_GetResourceAmount(pod, "coolant") > c_dec) then
								RD_ConsumeResource(pod, c_dec)
								heatsafe = 1
							end
						end
					end
					crushsafe = 1
				end
				
				--my own stuff
				if EnvShields then
					local shields = ents.FindByClass( "sent_personalshield" )
					for _, ent in pairs(shields) do
						if ent:IsValid() then
							if (ent:GetPos():Distance(entpos)) < 51 then
								crushsafe = 1 --doesn't give you air but keeps out pressure
								heatsafe  = 1 --stableises temp
								break
							end
						end
					end
				end
				
				if (airsafe == 0) then
					local ents2 = ents.FindByClass( "air_exchanger" )
					for _, ent2 in ipairs( ents2 ) do
						if ent2:IsValid() then
							if ((ent2.Active or 0) == 1) then
								if (ent2:GetPos():Distance(entpos) < (ent2.range or 0)) then
									if ((ent2.running or 0) == 1) then
										airsafe = 1
									end
									crushsafe = 1
									break
								end
							end
						end
					end
				end
				
				if (heatsafe == 0) then
					local ents2 = ents.FindByClass( "heat_exchanger" )
					for _, ent2 in ipairs( ents2 ) do
						if ent2:IsValid() then
							if ((ent2.running or 0) == 1) then
								if (ent2:GetPos():Distance(entpos) < (ent2.range or 0)) then
									heatsafe = 1
									break
								end
							end
						end
					end
				end
				
				if ((airsafe == 0) or (heatsafe == 0)) then
					local ents2 = ents.FindByClass( "climate_control" )
					for _, ent2 in ipairs( ents2 ) do
						if ent2:IsValid() then
							if (ent2.Active == 1) then
								if (ent2:GetPos():Distance(entpos) < (ent2.range or 0)) then
									if ((ent2.heat_running or 0) == 1) then
										heatsafe = 1
									end
									if ((ent2.air_running or 0) == 1) then
										airsafe = 1
									end
									crushsafe = 1
								end
							end
						end
					end
				end
		
				if (airsafe == 0) then
					if ((pPlayer.suit.habitat == 0) or (pPlayer.suit.inwater)) then
						hfix = 1
						Air_Update( pPlayer.suit )
					end
				end
				if (heatsafe == 0) then
					if (pPlayer.suit.temperature != FairTemp) then
						tfix = 1
						Temperature_Update( pPlayer.suit )
					end
				else
				end
				if (crushsafe == 0) then
					if (pPlayer.suit.atmosphere != 1) then
						Pressure_Update( pPlayer.suit )
					end
				end
			else
				if (pPlayer.suit.air < 100) then
					pPlayer.suit.air = 100
				end
				if (hfix == 1) then
					hfix = 0
				end
				if (tfix == 1) then
					tfix = 0
				end
			end
			if ( pPlayer.suit.air > 0 ) then
				if ( pPlayer.suit.recover > 0 ) then
					if (( pPlayer.Entity:Health() + 5 ) >= 100 ) then
						pPlayer.Entity:SetHealth(100)
						pPlayer.suit.recover = 0
					else
						pPlayer.Entity:SetHealth(pPlayer.Entity:Health() + 5)
						pPlayer.suit.recover = pPlayer.suit.recover - 5
					end
				end
			end
			if pPlayer:Alive() then Suit_Update( pPlayer.suit ) end
		end
	end
end
hook.Add( "Think", "Life_Support_Update", Life_Support_Update )


function SpawnFunc( ply )
	if (ply.suit == nil) then Suit_Register( ply ) end
end
hook.Add( "PlayerSpawn", "LS_SpawnFunc", SpawnFunc )


function ColorDamage(Entity, HP, Col)
	if (Entity.health <= (Entity.max_health / HP)) then
		Entity:SetColor(Col, Col, Col, 255)
	end
end

function DamageLS(Entity, Amount)
	Amount = math.floor(Amount / 2)
	if Entity.health == nil then --bug crash protection
		return true
	end
	if (Entity.health > 0) then
		local HP = Entity.health - Amount
		
		Entity.health = HP
		
		if (Entity.health <= (Entity.max_health / 2)) then
			Entity:Damage()
		end
	
		ColorDamage(Entity, 2, 200)
		ColorDamage(Entity, 3, 175)
		ColorDamage(Entity, 4, 150)
		ColorDamage(Entity, 5, 125)
		ColorDamage(Entity, 6, 100)
		ColorDamage(Entity, 7, 75)
		
		if (Entity.health <= 0) then
		
			Entity:SetColor(50, 50, 50, 255)
			
			if Entity:IsValid() then
				Entity:Destruct()
			end
		end
	end
end

function LSTakeDamage(Entity, One, Two, Damage)
	DamageLS(Entity, Damage)
end
hook.Add("EntityTakeDamage", "LSTakeDamage", LSTakeDamage)




function Register_Brushes ()
	local isClimate
	local brushes = ents.FindByClass( "logic_case" )
	for _, ent in ipairs( ents ) do
		isClimate = 0
		local hash = { }
		local values = ent:GetKeyValues()
		for key, value in pairs(values) do
   			if ((key == "Case01") and (value == "climate_brush")) then isClimate = 1 end
			if (key == "Case02") then hash.atmosphere = tonumber(value) end
			if (key == "Case03") then hash.temperature = tonumber(value) end
			if (key == "Case16") then hash.flags = tonumber(value) end
		end
		if (isClimate == 1) then
--			InSpace = 1
			hash.ent = ent
			hash.pos = ent:GetPos()
			hash.habitat = Extract_Bit(1, hash.flags)
			hash.unstable = Extract_Bit(2, hash.flags)
			hash.sunburn = Extract_Bit(4, hash.flags)
--			table.insert( planets, hash )
		end
	end
	Msg ( "Registered " .. #planets .. " planets\n" )
end

function Wire_BuildDupeInfo( ent )
	if (not ent.Inputs) then return end
	
	local info = { Wires = {} }
	for k,input in pairs(ent.Inputs) do
		if (input.Src) and (input.Src:IsValid()) then
		    info.Wires[k] = {
				StartPos = input.StartPos,
				Material = input.Material,
				Color = input.Color,
				Width = input.Width,
				Src = input.Src:EntIndex(),
				SrcId = input.SrcId,
				SrcPos = Vector(0, 0, 0),
			}
			
			if (input.Path) then
				info.Wires[k].Path = {}
				
			    for _,v in ipairs(input.Path) do
			        if (v.Entity) and (v.Entity:IsValid()) then
			        	table.insert(info.Wires[k].Path, { Entity = v.Entity:EntIndex(), Pos = v.Pos })
					end
			    end
			    
			    local n = table.getn(info.Wires[k].Path)
			    if (n > 0) and (info.Wires[k].Path[n].Entity == info.Wires[k].Src) then
			        info.Wires[k].SrcPos = info.Wires[k].Path[n].Pos
			        table.remove(info.Wires[k].Path, n)
			    end
			end
		end
	end
	
	return info
end

function Wire_ApplyDupeInfo(ply, ent, info, GetEntByID)
	if (info.Wires) then
		for k,input in pairs(info.Wires) do
		    
			Wire_Link_Start(ply:UniqueID(), ent, input.StartPos, k, input.Material, input.Color, input.Width)
		    
			if (input.Path) then
		        for _,v in ipairs(input.Path) do
					
					local ent2 = GetEntByID(v.Entity)
					if (!ent2) or (!ent2:IsValid()) then ent2 = ents.GetByIndex(v.Entity) end
					if (ent2) or (ent2:IsValid()) then
						Wire_Link_Node(ply:UniqueID(), ent2, v.Pos)
					else
						Msg("ApplyDupeInfo: Error, Could not find the entity for wire path\n")
					end
				end
		    end
			
			local ent2 = GetEntByID(input.Src)
		    if (!ent2) or (!ent2:IsValid()) then ent2 = ents.GetByIndex(input.Src) end
			if (ent2) or (ent2:IsValid()) then
				Wire_Link_End(ply:UniqueID(), ent2, input.SrcPos, input.SrcId)
			else
				Msg("ApplyDupeInfo: Error, Could not find the output entity\n")
			end
		end
	end
end
-- shanjaq: End Life Support mod.
